package org.xyl.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.xyl.dto.*;
import org.xyl.engine.EnterpriseRAGService;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;

/**
 * 企业级RAG控制器，提供REST API接口
 * 支持文档上传、文档处理、RAG查询等功能
 */
@RestController
@RequestMapping("/api/enterprise-rag")
public class EnterpriseRAGController {

    private static final Logger logger = LoggerFactory.getLogger(EnterpriseRAGController.class);
    private static final String TEMP_DIR = System.getProperty("java.io.tmpdir") + File.separator + "rag_uploads";

    @Autowired
    @Qualifier("enterpriseRagService")
    private EnterpriseRAGService ragService;

    static {
        // 初始化临时目录
        File tempDirectory = new File(TEMP_DIR);
        if (!tempDirectory.exists()) {
            tempDirectory.mkdirs();
        }
    }

    /**
     * RAG查询接口
     * @param request 查询请求
     * @return 查询结果
     */
    @PostMapping("/query")
    public ResponseEntity<RAGResponse> ragQuery(@RequestBody RAGRequest request) {
        try {
            logger.info("接收RAG查询请求: {}", request.getQuestion());
            RAGResponse response = ragService.ragQuery(
                    request.getQuestion(), 
                    request.getVectorLibraryName());
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            logger.error("RAG查询失败", e);
            RAGResponse errorResponse = new RAGResponse();
            errorResponse.setAnswer("查询处理失败: " + e.getMessage());
            errorResponse.setFallbackUsed(true);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(errorResponse);
        }
    }

    /**
     * 处理文档接口（通过路径）
     * @param request 文档处理请求
     * @return 处理结果
     */
    @PostMapping("/ingest")
    public ResponseEntity<String> ingestDocument(@RequestBody DocumentRequest request) {
        try {
            logger.info("接收文档处理请求: {}", request.getDocumentPath());
            ragService.processDocument(request.getDocumentPath());
            return ResponseEntity.ok("文档处理成功: " + request.getDocumentPath());
        } catch (Exception e) {
            logger.error("文档处理失败", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("文档处理失败: " + e.getMessage());
        }
    }

    /**
     * 异步处理文档接口
     * @param request 文档处理请求
     * @return 处理任务ID
     */
    @PostMapping("/ingest/async")
    public ResponseEntity<AsyncTaskResponse> ingestDocumentAsync(@RequestBody DocumentRequest request) {
        try {
            logger.info("接收异步文档处理请求: {}", request.getDocumentPath());
            CompletableFuture<String> future = ragService.processDocumentAsync(request.getDocumentPath());
            String taskId = UUID.randomUUID().toString();
            return ResponseEntity.accepted()
                    .body(new AsyncTaskResponse(taskId, "文档处理已启动"));
        } catch (Exception e) {
            logger.error("异步文档处理启动失败", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(new AsyncTaskResponse(null, "文档处理启动失败: " + e.getMessage()));
        }
    }

    /**
     * 文件上传并处理接口
     * @param file 上传的文件
     * @return 处理结果
     */
    @PostMapping("/upload-and-ingest")
    public ResponseEntity<String> uploadAndIngestFile(@RequestParam("file") MultipartFile file) {
        try {
            logger.info("接收文件上传: {}", file.getOriginalFilename());
            
            // 保存文件到临时目录
            String filename = UUID.randomUUID() + "_" + file.getOriginalFilename();
            Path filePath = Paths.get(TEMP_DIR, filename);
            Files.write(filePath, file.getBytes());
            
            // 处理文件
            ragService.processDocument(filePath.toString());
            
            // 删除临时文件
            Files.deleteIfExists(filePath);
            
            return ResponseEntity.ok("文件处理成功: " + file.getOriginalFilename());
        } catch (IOException e) {
            logger.error("文件保存失败", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("文件保存失败: " + e.getMessage());
        } catch (Exception e) {
            logger.error("文件处理失败", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("文件处理失败: " + e.getMessage());
        }
    }
    
    /**
     * 分片上传初始化接口
     * @param uploadRequest 上传请求参数
     * @return 初始化结果
     */
    @PostMapping("/upload/chunk/init")
    public ResponseEntity<Map<String, String>> initChunkUpload(@RequestBody ChunkUploadRequest uploadRequest) {
        try {
            logger.info("初始化分片上传: {}", uploadRequest.getFilename());
            
            // 生成唯一的上传ID
            String uploadId = UUID.randomUUID().toString();
            
            // 创建分片临时目录
            Path chunkDir = Paths.get(TEMP_DIR, "chunks", uploadId);
            Files.createDirectories(chunkDir);
            
            return ResponseEntity.ok(Map.of(
                "uploadId", uploadId,
                "message", "分片上传初始化成功"
            ));
        } catch (Exception e) {
            logger.error("分片上传初始化失败", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(Map.of("error", "分片上传初始化失败: " + e.getMessage()));
        }
    }
    
    /**
     * 分片上传接口
     * @param uploadId 上传ID
     * @param chunkIndex 分片索引
     * @param totalChunks 总分片数
     * @param file 分片文件数据
     * @return 分片上传结果
     */
    @PostMapping("/upload/chunk")
    public ResponseEntity<Map<String, String>> uploadChunk(
            @RequestParam("uploadId") String uploadId,
            @RequestParam("chunkIndex") int chunkIndex,
            @RequestParam("totalChunks") int totalChunks,
            @RequestParam("file") MultipartFile file) {
        try {
            logger.info("接收分片: uploadId={}, chunkIndex={}/{}", uploadId, chunkIndex, totalChunks);
            
            // 保存分片到临时目录
            Path chunkDir = Paths.get(TEMP_DIR, "chunks", uploadId);
            if (!Files.exists(chunkDir)) {
                return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                        .body(Map.of("error", "无效的uploadId或分片目录不存在"));
            }
            
            Path chunkPath = chunkDir.resolve("chunk_" + chunkIndex);
            Files.write(chunkPath, file.getBytes());
            
            return ResponseEntity.ok(Map.of(
                "message", "分片上传成功",
                "chunkIndex", String.valueOf(chunkIndex)
            ));
        } catch (Exception e) {
            logger.error("分片上传失败", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(Map.of("error", "分片上传失败: " + e.getMessage()));
        }
    }
    
    /**
     * 分片上传完成接口，合并分片并处理文件
     * @param completeRequest 合并请求参数
     * @return 处理结果
     */
    @PostMapping("/upload/chunk/complete")
    public ResponseEntity<String> completeChunkUpload(@RequestBody ChunkUploadCompleteRequest completeRequest) {
        try {
            String uploadId = completeRequest.getUploadId();
            String filename = completeRequest.getFilename();
            int totalChunks = completeRequest.getTotalChunks();
            
            logger.info("完成分片上传: uploadId={}, filename={}, totalChunks={}", uploadId, filename, totalChunks);
            
            // 分片目录
            Path chunkDir = Paths.get(TEMP_DIR, "chunks", uploadId);
            if (!Files.exists(chunkDir)) {
                return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                        .body("无效的uploadId或分片目录不存在");
            }
            
            // 合并分片到完整文件
            String finalFilename = UUID.randomUUID() + "_" + filename;
            Path finalFilePath = Paths.get(TEMP_DIR, finalFilename);
            
            try (java.io.FileOutputStream fos = new java.io.FileOutputStream(finalFilePath.toFile())) {
                for (int i = 0; i < totalChunks; i++) {
                    Path chunkPath = chunkDir.resolve("chunk_" + i);
                    if (!Files.exists(chunkPath)) {
                        throw new IOException("分片 " + i + " 不存在");
                    }
                    
                    byte[] chunkData = Files.readAllBytes(chunkPath);
                    fos.write(chunkData);
                    fos.flush();
                    
                    // 删除已合并的分片
                    Files.deleteIfExists(chunkPath);
                }
            }
            
            // 删除分片目录
            java.nio.file.Files.walkFileTree(chunkDir, new java.nio.file.SimpleFileVisitor<Path>() {
                @Override
                public java.nio.file.FileVisitResult visitFile(Path file, java.nio.file.attribute.BasicFileAttributes attrs) throws IOException {
                    java.nio.file.Files.delete(file);
                    return java.nio.file.FileVisitResult.CONTINUE;
                }
                
                @Override
                public java.nio.file.FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                    java.nio.file.Files.delete(dir);
                    return java.nio.file.FileVisitResult.CONTINUE;
                }
            });
            
            // 处理完整文件
            ragService.processDocument(finalFilePath.toString());
            
            // 删除临时文件
            Files.deleteIfExists(finalFilePath);
            
            return ResponseEntity.ok("文件合并并处理成功: " + filename);
        } catch (IOException e) {
            logger.error("文件合并失败", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("文件合并失败: " + e.getMessage());
        } catch (Exception e) {
            logger.error("文件处理失败", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("文件处理失败: " + e.getMessage());
        }
    }

    /**
     * 批量处理文档接口
     * @param request 批量文档请求
     * @return 处理结果
     */
    @PostMapping("/ingest/batch")
    public ResponseEntity<String> batchIngestDocuments(@RequestBody BatchDocumentRequest request) {
        try {
            logger.info("接收批量文档处理请求，文档数量: {}", request.getDocumentPaths().size());
            ragService.batchProcessDocuments(request.getDocumentPaths());
            return ResponseEntity.ok("批量文档处理成功，处理了 " + request.getDocumentPaths().size() + " 个文档");
        } catch (Exception e) {
            logger.error("批量文档处理失败", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("批量文档处理失败: " + e.getMessage());
        }
    }

    /**
     * 清空向量存储接口
     * @return 操作结果
     */
    @DeleteMapping("/vector-store")
    public ResponseEntity<String> clearVectorStore() {
        try {
            logger.info("接收清空向量存储请求");
            ragService.clearVectorStore();
            return ResponseEntity.ok("向量存储已清空");
        } catch (Exception e) {
            logger.error("清空向量存储失败", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("清空向量存储失败: " + e.getMessage());
        }
    }

    /**
     * 获取向量存储状态接口
     * @return 存储状态信息
     */
    @GetMapping("/vector-store/stats")
    public ResponseEntity<Map<String, Object>> getVectorStoreStats() {
        try {
            logger.info("接收获取向量存储状态请求");
            Map<String, Object> stats = ragService.getVectorStoreStats();
            return ResponseEntity.ok(stats);
        } catch (Exception e) {
            logger.error("获取向量存储状态失败", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(Map.of("error", "获取向量存储状态失败: " + e.getMessage()));
        }
    }

    /**
     * 健康检查接口
     * @return 健康状态
     */
    @GetMapping("/health")
    public ResponseEntity<Map<String, String>> healthCheck() {
        return ResponseEntity.ok(Map.of(
                "status", "healthy",
                "service", "enterprise-rag"
        ));
    }
}